package com.ds.infrastructure.hyperspace.console.service.impl;

import com.ds.infrastructure.hyperspace.console.common.methodlock.MethodLock;
import com.ds.infrastructure.hyperspace.console.common.methodlock.MethodLockId;
import com.ds.infrastructure.hyperspace.console.constants.ConsoleConstant;
import com.ds.infrastructure.hyperspace.console.constants.MethodLockConstant;
import com.ds.infrastructure.hyperspace.console.dao.dao.TbContainerConfigDao;
import com.ds.infrastructure.hyperspace.console.dto.configdata.ContainerDataDTO;
import com.ds.infrastructure.hyperspace.console.entity.enums.TbContainerConfigEnum;
import com.ds.infrastructure.hyperspace.console.entity.enums.TbPublicEnum;
import com.ds.infrastructure.hyperspace.console.entity.page.TbPageWhere;
import com.ds.infrastructure.hyperspace.console.entity.table.TbContainerConfig;
import com.ds.infrastructure.hyperspace.console.entity.where.TbContainerConfigCustomWhere;
import com.ds.infrastructure.hyperspace.console.entity.where.TbCustomWhere;
import com.ds.infrastructure.hyperspace.console.exceptions.ArgumentValidException;
import com.ds.infrastructure.hyperspace.console.exceptions.HyperspaceException;
import com.ds.infrastructure.hyperspace.console.service.inf.IContainerConfigService;
import com.ds.infrastructure.hyperspace.console.utils.FastJsonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/**
 * @author: yaozhendong
 * @create: 2019-09-18 18:38
 **/

@Service
public class ContainerConfigService implements IContainerConfigService {

    @Autowired
    TbContainerConfigDao tbContainerConfigDao;

    @Override
    public int save(TbContainerConfig record) {
        return tbContainerConfigDao.insertSelective(record);
    }

    @Override
    public int update(TbContainerConfig record) {
        return tbContainerConfigDao.updateByPrimaryKeySelective(record);
    }

    @Override
    public TbContainerConfig get(Long id) {
        TbContainerConfig entity = tbContainerConfigDao.selectByPrimaryKey(id);
        if (entity != null && TbPublicEnum.GMD_IS_DEL.NO.code.equals(entity.getGmtIsDeleted())) {
            return entity;
        }
        return null;
    }

    @Override
    public int delete(Long id) {
        TbContainerConfig item = new TbContainerConfig();
        item.setId(id);
        item.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.YES.code);
        return update(item);
    }

    @Override
    public List<TbContainerConfig> getList(TbContainerConfig where, TbCustomWhere customWhere, TbPageWhere pageWhere) {
        return tbContainerConfigDao.selectListForPage(where, customWhere, pageWhere);
    }

    @Override
    public int getTotal(TbContainerConfig where, TbCustomWhere customWhere) {
        return tbContainerConfigDao.selectListForPageCount(where, customWhere);
    }

    @Override
    public TbContainerConfig selectOne(TbContainerConfig where, TbCustomWhere customWhere) {
        List<TbContainerConfig> itemList = tbContainerConfigDao.selectListForPage(where, customWhere, TbPageWhere.newPage4OnlyOne());
        return itemList.stream().findFirst().orElseGet(() -> null);
    }

    @Override
    public TbContainerConfig getOrThrow(Long id) {
        return getOrThrow(id, null);
    }

    @Override
    public TbContainerConfig getOrThrow(Long id, String exceptionTitle) {

        TbContainerConfig entity = get(id);
        if (entity == null) {
            String error = String.format("%s:没有找到对应的记录;当前id=%s", exceptionTitle == null ? "获取网关配置信息失败" : exceptionTitle, id);
            throw new ArgumentValidException(error);
        }
        return entity;
    }

    @Override
    public boolean isExist(Long id) {
        return get(id) != null;
    }

    @Override
    public Integer selectMaxForConfigVersion(TbContainerConfig where, TbCustomWhere mapWhere) {
        return tbContainerConfigDao.selectMaxForConfigVersion(where, mapWhere);
    }

    @Override
    public void commit(MethodLockId methodLockId, TbContainerConfig entity, String userName, String userId) {
        updateEditState(entity, userName, userId);
        copy(entity);
    }

    private void updateEditState(TbContainerConfig entity, String userName, String userId) {
        TbContainerConfig newEntity = new TbContainerConfig();
        newEntity.setId(entity.getId());
        newEntity.setDescription(entity.getDescription());
        newEntity.setGmtModified(entity.getGmtModified());
        newEntity.setEditState(TbContainerConfigEnum.EDIT_STATE.NO.code);
        newEntity.setUserId(userId);
        newEntity.setUserName(userName);
        updateWithTimestamp(newEntity);
    }

    private void copy(TbContainerConfig entity) {
        TbContainerConfig newEntity = new TbContainerConfig();
        newEntity.setStageId(entity.getStageId());
        newEntity.setEnvironmentId(entity.getEnvironmentId());
        newEntity.setConfigDataVersion(entity.getConfigDataVersion());
        newEntity.setEditState(TbContainerConfigEnum.EDIT_STATE.YES.code);
        newEntity.setConfigData(entity.getConfigData());
        newEntity.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.NO.code);
        saveWithConfigVersion(newEntity);
    }

    @Override
    public TbContainerConfig selectLastOne(Long stageId, Long environmentId) {
        TbContainerConfig where = new TbContainerConfig();
        where.setStageId(stageId);
        where.setEnvironmentId(environmentId);
        where.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.NO.code);
        TbCustomWhere customWhere = new TbContainerConfigCustomWhere().setOrderByType(TbPublicEnum.ORDER_BY_TYPE.ID_DESC.value);
        TbContainerConfig entity = selectOne(where, customWhere);
        if (entity == null) {
            return null;
        }
        return get(entity.getId());

    }

    @Override
    @MethodLock(name = MethodLockConstant.CONTAINER_CONFIG_SERVICE_FOR_GET_LAST_ONE_METHOD)
    public TbContainerConfig getLastOneWithMethodLockId(MethodLockId methodLockId, Long stageId, Long environmentId) {
        TbContainerConfig entity = selectLastOne(stageId, environmentId);
        if (entity != null) {
            return entity;
        }
        TbContainerConfig newEntity = createDefaultEntity(environmentId, stageId);
        saveWithConfigVersion(newEntity);
        //获取最新时间戳
        return get(newEntity.getId());
    }

    @Override
    public int updateWithTimestamp(TbContainerConfig entity) {
        int count = tbContainerConfigDao.updateWithTimestamp(entity);
        if (count == 0) {
            throw new HyperspaceException("数据时间戳不一致。当前记录已被修改");
        }
        return count;
    }

    @Override
    public int rollback(TbContainerConfig entity) {
        TbContainerConfig lastEntity = selectLastOne(entity.getStageId(), entity.getEnvironmentId());
        if (!TbContainerConfigEnum.EDIT_STATE.YES.code.equals(lastEntity.getEditState())) {
            throw new HyperspaceException("最新配置的编辑状态为不可编辑，id=" + lastEntity.getId());
        }
        TbContainerConfig newEntity = new TbContainerConfig();
        newEntity.setId(lastEntity.getId());
        newEntity.setGmtModified(lastEntity.getGmtModified());
        newEntity.setConfigData(entity.getConfigData());
        newEntity.setConfigDataVersion(entity.getConfigDataVersion());
        return updateWithTimestamp(newEntity);
    }

    private void saveWithConfigVersion(TbContainerConfig entity) {
        int maxConfigVersion = selectMaxForConfigVersionByStageId(entity.getStageId());
        entity.setConfigVersion(++maxConfigVersion);
        save(entity);
    }

    private TbContainerConfig createDefaultEntity(Long environmentId, Long stageId) {
        TbContainerConfig tbContainerConfig = new TbContainerConfig();
        tbContainerConfig.setStageId(stageId);
        tbContainerConfig.setEnvironmentId(environmentId);
        tbContainerConfig.setConfigData(FastJsonUtil.serialize(new ContainerDataDTO()));
        tbContainerConfig.setConfigDataVersion(ConsoleConstant.CONTAINER_CONFIG_DATA_VERSION);
        tbContainerConfig.setEditState(TbContainerConfigEnum.EDIT_STATE.YES.code);
        tbContainerConfig.setGmtModified(new Date());
        tbContainerConfig.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.NO.code);
        return tbContainerConfig;
    }

    public int selectMaxForConfigVersionByStageId(Long stageId) {
        TbContainerConfig where = new TbContainerConfig();
        where.setStageId(stageId);
        where.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.NO.code);
        Integer maxId = selectMaxForConfigVersion(where, null);
        return maxId == null ? 0 : maxId;
    }
}
